// jQuery Slider Plugin
// Egor Khmelev - http://blog.egorkhmelev.com/ - hmelyoff@gmail.com

(function(){

    // Simple Inheritance
    Function.prototype.inheritFrom = function(BaseClass, oOverride){
        var Inheritance = function() {};
        Inheritance.prototype = BaseClass.prototype;
        this.prototype = new Inheritance();
        this.prototype.constructor = this;
        this.prototype.baseConstructor = BaseClass;
        this.prototype.superClass = BaseClass.prototype;

        if(oOverride){
            for(var i in oOverride) {
                this.prototype[i] = oOverride[i];
            }
        }
    };
  
    // Format numbers
    Number.prototype.jSliderNice=function(iRoundBase){
        var re=/^(-)?(\d+)([\.,](\d+))?$/;
        var iNum=Number(this);
        var sNum=String(iNum);
        var aMatches;
        var sDecPart='';
        var sTSeparator=' ';
        if((aMatches = sNum.match(re))){
            var sIntPart=aMatches[2];
            var iDecPart=(aMatches[4]) ? Number('0.'+aMatches[4]) : 0;
            if(iDecPart){
                var iRF=Math.pow(10, (iRoundBase) ? iRoundBase : 2);
                iDecPart=Math.round(iDecPart*iRF);
                sNewDecPart=String(iDecPart);
                sDecPart = sNewDecPart;
                if(sNewDecPart.length < iRoundBase){
                    var iDiff = iRoundBase-sNewDecPart.length;
                    for (var i=0; i < iDiff; i++) {
                        sDecPart = "0" + sDecPart;
                    };
                }
                sDecPart = "," + sDecPart;
            } else {
                if(iRoundBase && iRoundBase != 0){
                    for (var i=0; i < iRoundBase; i++) {
                        sDecPart += "0";
                    };
                    sDecPart = "," + sDecPart;
                }
            }
            var sResult;
            if(Number(sIntPart) < 1000){
                sResult = sIntPart+sDecPart;
            }else{
                var sNewNum='';
                var i;
                for(i=1; i*3<sIntPart.length; i++)
                    sNewNum=sTSeparator+sIntPart.substring(sIntPart.length - i*3, sIntPart.length - (i-1)*3)+sNewNum;
                sResult = sIntPart.substr(0, 3 - i*3 + sIntPart.length)+sNewNum+sDecPart;
            }
            if(aMatches[1])
                return '-'+sResult;
            else
                return sResult;
        }
        else{
            return sNum;
        }
    };

    this.jSliderIsArray = function( value ){
        if( typeof value == "undefined" ) return false;
    
        if (value instanceof Array ||  // Works quickly in same execution context.
            // If value is from a different execution context then
            // !(value instanceof Object), which lets us early out in the common
            // case when value is from the same context but not an array.
            // The {if (value)} check above means we don't have to worry about
            // undefined behavior of Object.prototype.toString on null/undefined.
            //
            // HACK: In order to use an Object prototype method on the arbitrary
            //   value, the compiler requires the value be cast to type Object,
            //   even though the ECMA spec explicitly allows it.
            (!(value instanceof Object) &&
                (Object.prototype.toString.call(
                    /** @type {Object} */ (value)) == '[object Array]') ||

                // In IE all non value types are wrapped as objects across window
                // boundaries (not iframe though) so we have to do object detection
                // for this edge case
                typeof value.length == 'number' &&
                typeof value.splice != 'undefined' &&
                typeof value.propertyIsEnumerable != 'undefined' &&
                !value.propertyIsEnumerable('splice')

                )) {
            return true;
        }
    
        return false;
    }
  
  
})();


// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed

(function(){
    var cache = {};
  
    this.jSliderTmpl = function jSliderTmpl(str, data){
        // Figure out if we're getting a template, or if we need to
        // load the template - and be sure to cache the result.
        var fn = !(/\W/).test(str) ?
        cache[str] = cache[str] ||
        jSliderTmpl(str) :
      
        // Generate a reusable function that will serve as a template
        // generator (and which will be cached).
        new Function("obj",
            "var p=[],print=function(){p.push.apply(p,arguments);};" +
        
            // Introduce the data as local variables using with(){}
            "with(obj){p.push('" +
        
            // Convert the template into pure JavaScript
            str
            .replace(/[\r\t\n]/g, " ")
            .split("<%").join("\t")
            .replace(/((^|%>)[^\t]*)'/g, "$1\r")
            .replace(/\t=(.*?)%>/g, "',$1,'")
            .split("\t").join("');")
            .split("%>").join("p.push('")
            .split("\r").join("\\'")
            + "');}return p.join('');");
    
        // Provide some basic currying to the user
        return data ? fn( data ) : fn;
    };
})();


// Draggable Class
// Egor Khmelev - http://blog.egorkhmelev.com/

(function( $ ){

    this.Draggable = function(){
        this._init.apply( this, arguments );
    };

    Draggable.prototype = {
        // Methods for re-init in child class
        oninit: function(){},
        events: function(){},
        onmousedown: function(){
            this.ptr.css({
                position: "absolute"
            });
        },
        onmousemove: function( evt, x, y ){
            this.ptr.css({
                left: x, 
                top: y
            });
        },
        onmouseup: function(){},

        isDefault: {
            drag: false,
            clicked: false,
            toclick: true,
            mouseup: false
        },

        _init: function(){
            if( arguments.length > 0 ){
                this.ptr = $(arguments[0]);
                this.outer = $(".draggable-outer");

                this.is = {};
                $.extend( this.is, this.isDefault );

                var _offset = this.ptr.offset();
                this.d = {
                    left: _offset.left,
                    top: _offset.top,
                    width: this.ptr.width(),
                    height: this.ptr.height()
                };

                this.oninit.apply( this, arguments );

                this._events();
            }
        },
        _getPageCoords: function( event ){
            if( event.targetTouches && event.targetTouches[0] ){
                return {
                    x: event.targetTouches[0].pageX, 
                    y: event.targetTouches[0].pageY
                };
            } else
                return {
                    x: event.pageX, 
                    y: event.pageY
                };
        },
        _bindEvent: function( ptr, eventType, handler ){
            var self = this;

            if( this.supportTouches_ )
                ptr.get(0).addEventListener( this.events_[ eventType ], handler, false );
  	  
            else
                ptr.bind( this.events_[ eventType ], handler );
        },
        _events: function(){
            var self = this;

            this.supportTouches_ = ( $.browser.webkit && navigator.userAgent.indexOf("Mobile") != -1 );
            this.events_ = {
                "click": this.supportTouches_ ? "touchstart" : "click",
                "down": this.supportTouches_ ? "touchstart" : "mousedown",
                "move": this.supportTouches_ ? "touchmove" : "mousemove",
                "up"  : this.supportTouches_ ? "touchend" : "mouseup"
            };

            this._bindEvent( $( document ), "move", function( event ){
                if( self.is.drag ){
                    event.stopPropagation();
                    event.preventDefault();
                    self._mousemove( event );
                }
            });
            this._bindEvent( $( document ), "down", function( event ){
                if( self.is.drag ){
                    event.stopPropagation();
                    event.preventDefault();
                }
            });
            this._bindEvent( $( document ), "up", function( event ){
                self._mouseup( event );
            });
			
            this._bindEvent( this.ptr, "down", function( event ){
                self._mousedown( event );
                return false;
            });
            this._bindEvent( this.ptr, "up", function( event ){
                self._mouseup( event );
            });
			
            this.ptr.find("a")
            .click(function(){
                self.is.clicked = true;

                if( !self.is.toclick ){
                    self.is.toclick = true;
                    return false;
                }
            })
            .mousedown(function( event ){
                self._mousedown( event );
                return false;
            });

            this.events();
        },
        _mousedown: function( evt ){
            this.is.drag = true;
            this.is.clicked = false;
            this.is.mouseup = false;

            var _offset = this.ptr.offset();
            var coords = this._getPageCoords( evt );
            this.cx = coords.x - _offset.left;
            this.cy = coords.y - _offset.top;

            $.extend(this.d, {
                left: _offset.left,
                top: _offset.top,
                width: this.ptr.width(),
                height: this.ptr.height()
            });

            if( this.outer && this.outer.get(0) ){
                this.outer.css({
                    height: Math.max(this.outer.height(), $(document.body).height()), 
                    overflow: "hidden"
                });
            }

            this.onmousedown( evt );
        },
        _mousemove: function( evt ){
            this.is.toclick = false;
            var coords = this._getPageCoords( evt );
            this.onmousemove( evt, coords.x - this.cx, coords.y - this.cy );
        },
        _mouseup: function( evt ){
            var oThis = this;

            if( this.is.drag ){
                this.is.drag = false;

                if( this.outer && this.outer.get(0) ){

                    if( $.browser.mozilla ){
                        this.outer.css({
                            overflow: "hidden"
                        });
                    } else {
                        this.outer.css({
                            overflow: "visible"
                        });
                    }

                    if( $.browser.msie && $.browser.version == '6.0' ){
                        this.outer.css({
                            height: "100%"
                        });
                    } else {
                        this.outer.css({
                            height: "auto"
                        });
                    }	
                }

                this.onmouseup( evt );
            }
        }

    };

})( jQuery );



// jQuery Slider (Safari)
// Egor Khmelev - http://blog.egorkhmelev.com/

(function( $ ) {

    $.slider = function( node, settings ){
        var jNode = $(node);
        if( !jNode.data( "jslider" ) )
            jNode.data( "jslider", new jSlider( node, settings ) );
	  
        return jNode.data( "jslider" );
    };
	
    $.fn.slider = function( action, opt_value ){
        var returnValue, args = arguments;
	  
        function isDef( val ){
            return val !== undefined;
        };

        function isDefAndNotNull( val ){
            return val != null;
        };
	  
        this.each(function(){
            var self = $.slider( this, action );
		  
            // do actions
            if( typeof action == "string" ){
                switch( action ){
                    case "value":
                        if( isDef( args[ 1 ] ) && isDef( args[ 2 ] ) ){
                            var pointers = self.getPointers();
                            if( isDefAndNotNull( pointers[0] ) && isDefAndNotNull( args[1] ) ){
                                pointers[0].set( args[ 1 ] );
                                pointers[0].setIndexOver();
                            }
		          
                            if( isDefAndNotNull( pointers[1] ) && isDefAndNotNull( args[2] ) ){
                                pointers[1].set( args[ 2 ] );
                                pointers[1].setIndexOver();
                            }
                        }
		        
                        else if( isDef( args[ 1 ] ) ){
                            var pointers = self.getPointers();
                            if( isDefAndNotNull( pointers[0] ) && isDefAndNotNull( args[1] ) ){
                                pointers[0].set( args[ 1 ] );
                                pointers[0].setIndexOver();
                            }
                        }
		        
                        else
                            returnValue = self.getValue();

                        break;

                    case "prc":
                        if( isDef( args[ 1 ] ) && isDef( args[ 2 ] ) ){
                            var pointers = self.getPointers();
                            if( isDefAndNotNull( pointers[0] ) && isDefAndNotNull( args[1] ) ){
                                pointers[0]._set( args[ 1 ] );
                                pointers[0].setIndexOver();
                            }

                            if( isDefAndNotNull( pointers[1] ) && isDefAndNotNull( args[2] ) ){
                                pointers[1]._set( args[ 2 ] );
                                pointers[1].setIndexOver();
                            }
                        }

                        else if( isDef( args[ 1 ] ) ){
                            var pointers = self.getPointers();
                            if( isDefAndNotNull( pointers[0] ) && isDefAndNotNull( args[1] ) ){
                                pointers[0]._set( args[ 1 ] );
                                pointers[0].setIndexOver();
                            }
                        }

                        else
                            returnValue = self.getPrcValue();

                        break;

                    case "calculatedValue":
                        var value = self.getValue().split(";");
                        returnValue = "";
                        for (var i=0; i < value.length; i++) {
                            returnValue += (i > 0 ? ";" : "") + self.nice( value[i] );
                        };
  		      
                        break;
  		      
                    case "skin":
                        self.setSkin( args[1] );

                        break;
                };
		  
            }
		  
            // return actual object
            else if( !action && !opt_value ){
                if( !jSliderIsArray( returnValue ) )
                    returnValue = [];

                returnValue.push( slider );
            }
        });
		
        // flatten array just with one slider
        if( jSliderIsArray( returnValue ) && returnValue.length == 1 )
            returnValue = returnValue[ 0 ];
		
        return returnValue || this;
    };
  
    var OPTIONS = {

        settings: {
            from: 1,
            to: 10,
            step: 1,
            smooth: true,
            limits: true,
            round: 0,
            value: "5;7",
            dimension: ""
        },
    
        className: "jslider",
        selector: ".jslider-",

        template: jSliderTmpl(
            '<span class="<%=className%>">' +
            '<table><tr><td>' +
            '<div class="<%=className%>-bg">' +
            '<i class="l"><i></i></i><i class="r"><i></i></i>' +
            '<i class="v"><i></i></i>' +
            '</div>' +

            '<div class="<%=className%>-pointer"><i></i></div>' +
            '<div class="<%=className%>-pointer <%=className%>-pointer-to"><i></i></div>' +
        
            '<div class="<%=className%>-label"><span><%=settings.from%></span></div>' +
            '<div class="<%=className%>-label <%=className%>-label-to"><span><%=settings.to%></span><%=settings.dimension%></div>' +

            '<div class="<%=className%>-value"><span></span><%=settings.dimension%></div>' +
            '<div class="<%=className%>-value <%=className%>-value-to"><span></span><%=settings.dimension%></div>' +
          
            '<div class="<%=className%>-scale"><%=scale%></div>'+

            '</td></tr></table>' +
            '</span>'
            )
    
    };

    this.jSlider = function(){
        return this.init.apply( this, arguments );
    };

    jSlider.prototype = {
        init: function( node, settings ){
            this.settings = $.extend(true, {}, OPTIONS.settings, settings ? settings : {});
      
            // obj.sliderHandler = this;
            this.inputNode = $( node ).hide();
      						
            this.settings.interval = this.settings.to-this.settings.from;
            this.settings.value = this.inputNode.attr("value");
			
            if( this.settings.calculate && $.isFunction( this.settings.calculate ) )
                this.nice = this.settings.calculate;

            if( this.settings.onstatechange && $.isFunction( this.settings.onstatechange ) )
                this.onstatechange = this.settings.onstatechange;

            this.is = {
                init: false
            };
            this.o = {};

            this.create();
        },
    
        onstatechange: function(){},
    
        create: function(){
            var $this = this;
      
            this.domNode = $( OPTIONS.template({
                className: OPTIONS.className,
                settings: {
                    from: this.nice( this.settings.from ),
                    to: this.nice( this.settings.to ),
                    dimension: this.settings.dimension
                },
                scale: this.generateScale()
            }) );
      
            this.inputNode.after( this.domNode );
            this.drawScale();
      
            // set skin class
            if( this.settings.skin && this.settings.skin.length > 0 )
                this.setSkin( this.settings.skin );

            this.sizes = {
                domWidth: this.domNode.width(),
                domOffset: this.domNode.offset()
            };

            // find some objects
            $.extend(this.o, {
                pointers: {},
                labels: {
                    0: {
                        o: this.domNode.find(OPTIONS.selector + "value").not(OPTIONS.selector + "value-to")
                    },
                    1: {
                        o: this.domNode.find(OPTIONS.selector + "value").filter(OPTIONS.selector + "value-to")
                    }
                },
                limits: {
                    0: this.domNode.find(OPTIONS.selector + "label").not(OPTIONS.selector + "label-to"),
                    1: this.domNode.find(OPTIONS.selector + "label").filter(OPTIONS.selector + "label-to")
                }
            });

            $.extend(this.o.labels[0], {
                value: this.o.labels[0].o.find("span")
            });

            $.extend(this.o.labels[1], {
                value: this.o.labels[1].o.find("span")
            });

      
            if( !$this.settings.value.split(";")[1] ){
                this.settings.single = true;
                this.domNode.addDependClass("single");
            }

            if( !$this.settings.limits )
                this.domNode.addDependClass("limitless");

            this.domNode.find(OPTIONS.selector + "pointer").each(function( i ){
                var value = $this.settings.value.split(";")[i];
                if( value ){
                    $this.o.pointers[i] = new jSliderPointer( this, i, $this );

                    var prev = $this.settings.value.split(";")[i-1];
                    if( prev && new Number(value) < new Number(prev) ) value = prev;

                    value = value < $this.settings.from ? $this.settings.from : value;
                    value = value > $this.settings.to ? $this.settings.to : value;
        
                    $this.o.pointers[i].set( value, true );
                }
            });
      
            this.o.value = this.domNode.find(".v");
            this.is.init = true;
      
            $.each(this.o.pointers, function(i){
                $this.redraw(this);
            });
      
            (function(self){
                $(window).resize(function(){
                    self.onresize();
                });
            })(this);

        },
    
        setSkin: function( skin ){
            if( this.skin_ )
                this.domNode.removeDependClass( this.skin_, "_" );

            this.domNode.addDependClass( this.skin_ = skin, "_" );
        },
    
        setPointersIndex: function( i ){
            $.each(this.getPointers(), function(i){
                this.index( i );
            });
        },
    
        getPointers: function(){
            return this.o.pointers;
        },
    
        generateScale: function(){
            if( this.settings.scale && this.settings.scale.length > 0 ){
                var str = "";
                var s = this.settings.scale;
                var prc = Math.round((100/(s.length-1))*10)/10;
                for( var i=0; i < s.length; i++ ){
                    str += '<span style="left: ' + i*prc + '%">' + ( s[i] != '|' ? '<ins>' + s[i] + '</ins>' : '' ) + '</span>';
                };
                return str;
            } else return "";

            return "";
        },
    
        drawScale: function(){
            this.domNode.find(OPTIONS.selector + "scale span ins").each(function(){
                $(this).css({
                    marginLeft: -$(this).outerWidth()/2
                });
            });
        },
    
        onresize: function(){
            var self = this;
            this.sizes = {
                domWidth: this.domNode.width(),
                domOffset: this.domNode.offset()
            };

            $.each(this.o.pointers, function(i){
                self.redraw(this);
            });
        },
    
        limits: function( x, pointer ){
            // smooth
            if( !this.settings.smooth ){
                var step = this.settings.step*100 / ( this.settings.interval );
                x = Math.round( x/step ) * step;
            }
  	  
            var another = this.o.pointers[1-pointer.uid];
            if( another && pointer.uid && x < another.value.prc ) x = another.value.prc;
            if( another && !pointer.uid && x > another.value.prc ) x = another.value.prc;

            // base limit
            if( x < 0 ) x = 0;
            if( x > 100 ) x = 100;
  	  
            return Math.round( x*10 ) / 10;
        },
    
        redraw: function( pointer ){
            if( !this.is.init ) return false;
      
            this.setValue();
      
            // redraw range line
            if( this.o.pointers[0] && this.o.pointers[1] )
                this.o.value.css({
                    left: this.o.pointers[0].value.prc + "%", 
                    width: ( this.o.pointers[1].value.prc - this.o.pointers[0].value.prc ) + "%"
                });

            this.o.labels[pointer.uid].value.html(
                this.nice(
                    pointer.value.origin
                    )
                );
      
            // redraw position of labels
            this.redrawLabels( pointer );

        },
    
        redrawLabels: function( pointer ){

            function setPosition( label, sizes, prc ){
                sizes.margin = -sizes.label/2;

                // left limit
                label_left = sizes.border + sizes.margin;
                if( label_left < 0 )
                    sizes.margin -= label_left;

                // right limit
                if( sizes.border+sizes.label / 2 > self.sizes.domWidth ){
                    sizes.margin = 0;
                    sizes.right = true;
                } else
                    sizes.right = false;
          
                label.o.css({
                    left: prc + "%", 
                    marginLeft: sizes.margin, 
                    right: "auto"
                });
                if( sizes.right ) label.o.css({
                    left: "auto", 
                    right: 0
                });
                return sizes;
            }

            var self = this;
            var label = this.o.labels[pointer.uid];
            var prc = pointer.value.prc;

            var sizes = {
                label: label.o.outerWidth(),
                right: false,
                border: ( prc * this.sizes.domWidth ) / 100
            };

            //console.log(this.o.pointers[1-pointer.uid])
            if( !this.settings.single ){
                // glue if near;
                var another = this.o.pointers[1-pointer.uid];
                var another_label = this.o.labels[another.uid];

                switch( pointer.uid ){
                    case 0:
                        if( sizes.border+sizes.label / 2 > another_label.o.offset().left-this.sizes.domOffset.left ){
                            another_label.o.css({
                                visibility: "hidden"
                            });
                            another_label.value.html( this.nice( another.value.origin ) );

                            label.o.css({
                                visibility: "visible"
                            });

                            prc = ( another.value.prc - prc ) / 2 + prc;
                            if( another.value.prc != pointer.value.prc ){
                                label.value.html( this.nice(pointer.value.origin) + "&nbsp;&ndash;&nbsp;" + this.nice(another.value.origin) );
                                sizes.label = label.o.outerWidth();
                                sizes.border = ( prc * this.sizes.domWidth ) / 100;
                            }
                        } else {
                            another_label.o.css({
                                visibility: "visible"
                            });
                        }
                        break;

                    case 1:
                        if( sizes.border - sizes.label / 2 < another_label.o.offset().left - this.sizes.domOffset.left + another_label.o.outerWidth() ){
                            another_label.o.css({
                                visibility: "hidden"
                            });
                            another_label.value.html( this.nice(another.value.origin) );

                            label.o.css({
                                visibility: "visible"
                            });

                            prc = ( prc - another.value.prc ) / 2 + another.value.prc;
                            if( another.value.prc != pointer.value.prc ){
                                label.value.html( this.nice(another.value.origin) + "&nbsp;&ndash;&nbsp;" + this.nice(pointer.value.origin) );
                                sizes.label = label.o.outerWidth();
                                sizes.border = ( prc * this.sizes.domWidth ) / 100;
                            }
                        } else {
                            another_label.o.css({
                                visibility: "visible"
                            });
                        }
                        break;
                }
            }

            sizes = setPosition( label, sizes, prc );
      
            /* draw second label */
            if( another_label ){
                var sizes = {
                    label: another_label.o.outerWidth(),
                    right: false,
                    border: ( another.value.prc * this.sizes.domWidth ) / 100
                };
                sizes = setPosition( another_label, sizes, another.value.prc );
            }
  	  
            this.redrawLimits();
        },
    
        redrawLimits: function(){
            if( this.settings.limits ){

                var limits = [ true, true ];

                for( key in this.o.pointers ){

                    if( !this.settings.single || key == 0 ){
          
                        var pointer = this.o.pointers[key];
                        var label = this.o.labels[pointer.uid];
                        var label_left = label.o.offset().left - this.sizes.domOffset.left;

                        var limit = this.o.limits[0];
                        if( label_left < limit.outerWidth() )
                            limits[0] = false;

                        var limit = this.o.limits[1];
                        if( label_left + label.o.outerWidth() > this.sizes.domWidth - limit.outerWidth() )
                            limits[1] = false;
                    }

                };

                for( var i=0; i < limits.length; i++ ){
                    if( limits[i] )
                        this.o.limits[i].fadeIn("fast");
                    else
                        this.o.limits[i].fadeOut("fast");
                };

            }
        },
    
        setValue: function(){
            var value = this.getValue();
            this.inputNode.attr( "value", value );
            this.onstatechange.call( this, value );
        },
        getValue: function(){
            if(!this.is.init) return false;
            var $this = this;
      
            var value = "";
            $.each( this.o.pointers, function(i){
                if( this.value.prc != undefined && !isNaN(this.value.prc) ) value += (i > 0 ? ";" : "") + $this.prcToValue( this.value.prc );
            });
            return value;
        },
        getPrcValue: function(){
            if(!this.is.init) return false;
            var $this = this;
      
            var value = "";
            $.each( this.o.pointers, function(i){
                if( this.value.prc != undefined && !isNaN(this.value.prc) ) value += (i > 0 ? ";" : "") + this.value.prc;
            });
            return value;
        },
        prcToValue: function( prc ){

            if( this.settings.heterogeneity && this.settings.heterogeneity.length > 0 ){
                var h = this.settings.heterogeneity;

                var _start = 0;
                var _from = this.settings.from;

                for( var i=0; i <= h.length; i++ ){
                    if( h[i] ) var v = h[i].split("/");
                    else       var v = [100, this.settings.to];
    	    
                    v[0] = new Number(v[0]);
                    v[1] = new Number(v[1]);
    	      
                    if( prc >= _start && prc <= v[0] ) {
                        var value = _from + ( (prc-_start) * (v[1]-_from) ) / (v[0]-_start);
                    }

                    _start = v[0];
                    _from = v[1];
                };

            } else {
                var value = this.settings.from + ( prc * this.settings.interval ) / 100;
            }

            return this.round( value );
        },
    
        valueToPrc: function( value, pointer ){  	  
            if( this.settings.heterogeneity && this.settings.heterogeneity.length > 0 ){
                var h = this.settings.heterogeneity;

                var _start = 0;
                var _from = this.settings.from;

                for (var i=0; i <= h.length; i++) {
                    if(h[i]) var v = h[i].split("/");
                    else     var v = [100, this.settings.to];
                    v[0] = new Number(v[0]);
                    v[1] = new Number(v[1]);
    	      
                    if(value >= _from && value <= v[1]){
                        var prc = pointer.limits(_start + (value-_from)*(v[0]-_start)/(v[1]-_from));
                    }

                    _start = v[0];
                    _from = v[1];
                };

            } else {
                var prc = pointer.limits((value-this.settings.from)*100/this.settings.interval);
            }

            return prc;
        },
    
    
        round: function( value ){
            value = Math.round( value / this.settings.step ) * this.settings.step;
            if( this.settings.round ) value = Math.round( value * Math.pow(10, this.settings.round) ) / Math.pow(10, this.settings.round);
            else value = Math.round( value );
            return value;
        },
  	
        nice: function( value ){
            value = value.toString().replace(/,/gi, ".");
            value = value.toString().replace(/ /gi, "");
            if( Number.prototype.jSliderNice )
                return (new Number(value)).jSliderNice(this.settings.round).replace(/-/gi, "&minus;");
            else
                return new Number(value);
        }
    
    };
  
    function jSliderPointer(){
        this.baseConstructor.apply(this, arguments);
    }

    jSliderPointer.inheritFrom(Draggable, {
        oninit: function( ptr, id, _constructor ){
            this.uid = id;
            this.parent = _constructor;
            this.value = {};
            this.settings = this.parent.settings;
        },
        onmousedown: function(evt){
            this._parent = {
                offset: this.parent.domNode.offset(),
                width: this.parent.domNode.width()
            };
            this.ptr.addDependClass("hover");
            this.setIndexOver();
        },
        onmousemove: function( evt, x ){
            var coords = this._getPageCoords( evt );
            this._set( this.calc( coords.x ) );
        },
        onmouseup: function( evt ){
            // var coords = this._getPageCoords( evt );
            // this._set( this.calc( coords.x ) );

            if( this.parent.settings.callback && $.isFunction(this.parent.settings.callback) )
                this.parent.settings.callback.call( this.parent, this.parent.getValue() );
  	    
            this.ptr.removeDependClass("hover");
        },
  	
        setIndexOver: function(){
            this.parent.setPointersIndex( 1 );
            this.index( 2 );
        },
  	
        index: function( i ){
            this.ptr.css({
                zIndex: i
            });
        },
  	
        limits: function( x ){
            return this.parent.limits( x, this );
        },
  	
        calc: function(coords){
            var x = this.limits(((coords-this._parent.offset.left)*100)/this._parent.width);
            return x;
        },

        set: function( value, opt_origin ){
            this.value.origin = this.parent.round(value);
            this._set( this.parent.valueToPrc( value, this ), opt_origin );
        },  	
        _set: function( prc, opt_origin ){
            if( !opt_origin )
                this.value.origin = this.parent.prcToValue(prc);

            this.value.prc = prc;
            this.ptr.css({
                left: prc + "%"
            });
            this.parent.redraw(this);
        }
  	
    });
  
  
})(jQuery);





/* end */